The QRZ! Ham Radio CDROM Callsign Database Technical Specification Rev B May 1995 Note: the following information is provided for those who wish to access the callsign database information without the use of the QRZ! software. Users of the QRZ! Ham Radio CDROM who wish to write their own callsign database search and retrieval software are encouraged to do so. We welcome user contributed shareware programs for future versions of the QRZ! Ham Radio CDROM. PC VERSIONS For the PC, there are two versions of the QRZ! software, one for DOS and one for Windows 3.1. Both versions use the same copy of the database and the same primary search and retrieval methods. The QRZ callsign database indexing and retrieval method was designed and optimized for CDROM use. The primary goal was to provide fast access for searches in light of the fact that typical CDROM seek times are somewhat slow compared to hard disk. The algorithm described below implements a methodology which requires only one CDROM disc seek per lookup. The QRZ callsign database is composed of four copies of the data, each sorted by a different criteria. One copy is sorted by callsign, one by last name, one by city-state and one by zip code. Note that only the callsign database contains the foreign (DX) records. We would have liked to sort the DX callsigns by name and by city, etc., but could not since there is no universal address format. Therefore, DX callsigns can be fetched by callsign only. Each datafile has its own corresponding index file. An index file contains selected keys from the corresponding database sampled at regular intervals. The key sampling interval is stored in the index header as bytesperkey, as shown in the structure definition below. /* ** Index Header Block Definition (Version 2) ** (applies to all QRZ CDROMS from Version 2 onward) ** ** This block is located at the start of each index */ typedef struct { char dataname[16]; /* Name of the data file */ char bytesperkey[8]; /* Data Bytes per Index Item */ char numkeys[8]; /* Number of items in this index */ char keylen[8]; /* Length of each key item in bytes */ char version[8]; /* Database Version ID */ } index_header; Index Usage The name index is set to a maximum of 16 characters with longer names being truncated. Names are stored in last-first format with a space between the names. The city/state index uses 12 characters per entry, the callsign index 6 characters and the zip code index 5 characters. The data which follows the header is simply a long list of single field records. The records are tightly packed on 'bytesperkey' boundaries without separators. There is no guarantee of a null terminator on any index record entry. When the program qrz.exe is run it first searches for a drive containing the base directory \CALLBK . Next, it loads all four index files (callbkc.idx, callbkn.idx, callbks.idx and callbkz.idx) into tables in memory. These tables were kept small so as not to place an undue RAM requirement on the user's system. Next, when a user specifies a field and key to search, the program searches the relevant index table and returns the closest match lower (or equal to) the supplied key. The table position of this key is then taken and multiplied by the 'bytesperkey' value to arrive at a database file offset. This offset is then used to perform the first and only seek into the database. Once on position within the file, a sequential search is performed to return the match. The search terminates at the next index key value if the field is not found. The database files all have the same format. The records each consist of comma separated fields which end with a single newline '\n' (ASCII 0xa) character. Blank fields are simply stored as a comma. Every record has the same number of commas in it. Actual comma's in the data field are stored as a semi-colon ';' which should be replaced by a comma in the user's output formatting routine. Example: AA7BQ ,LLOYD,,FRED L,,53340,90009,00009,8215 E WOOD DR,SCOTTSDALE,AZ, 85260,E,KJ6RK,A /* ** Standard Record Field Offsets */ #define CALL 0 AA7BQ #define LNAME 1 LLOYD #define JR 2 (not used) *** #define FNAME 3 FRED L #define MI 4 (not used) *** #define DOB 5 53340 #define EFDATE 6 90009 #define EXPDATE 7 00009 #define MAIL_STR 8 8215 E. Wood DR #define MAIL_CITY 9 SCOTTSDALE #define MAIL_ST 10 AZ #define MAIL_ZIP 11 85260 #define CLASS 12 E #define P_CALL 13 KJ6RK #define P_CLASS 14 A *** The fields JR and MI were obsoleted by the FCC in July 1994. The callsign fields are arranged in a strict "ccdccc" columnar format where 'c' represents a letter and 'd' a digit. Callsigns which do not conform to the "ccdccc" format are space filled in the relevant positions. This field is rearranged to the proper layout by the user program's output formatting routines. All dates are stored in 5 character Julian format, e.g. 93003 equals January 3, 1993. Dates before 1900 or after year 2000 must be determined by their context usage. In other words, if the resultant age does not make sense, then it's wrong. For example, all licenses expire in the future so 02 is 2002. Birthdays are more difficult but most can be determined to be greater than 10 years old. This is not a perfect method, but it does yield satisfactory results. Some folks may notice that the database no longer contains station location information. This information is no longer supplied nor available from the FCC since it is no longer a part of their record keeping (See the May 1993 QST for more info). Cross Reference Information Callsigns in the database are now cross-referenced to both the current and the previous call sign for each entry in which they are available. A cross reference record takes the form of 'old,new' with no other information in the record. A record can be identified as a cross reference either one of two ways: First, if the record length is less than 15 characters, then it is a cross reference record. Secondly, if the record contains only one comma "," , then it is a cross reference record. It is not necessary to test for both cases, either will do. When a cross reference record is encountered, you must fetch the second field and restart the search to return the primary reference. ------------------------------------------------------------------- Fred Lloyd, AA7BQ 05/24/95